﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="SettingsProviderFactory.cs" company="DevDigital">
//   DevDigital
// </copyright>
// --------------------------------------------------------------------------------------------------------------------

namespace Settings.NET
{
    using System;
    using System.Collections.Generic;

    /// <summary>
    /// Settings provider factory
    /// </summary>
    [Serializable]
    public class SettingsProviderFactory : ISettingsProviderFactory
    {
        /// <summary>
        /// Collection of settings storage currently registered
        /// </summary>
        private readonly IDictionary<string, ISettingsStorage> storages = new Dictionary<string, ISettingsStorage>();

        /// <summary>
        /// Collection of settings serializers currently registered
        /// </summary>
        private readonly IDictionary<string, ISettingsSerializer> serializers = new Dictionary<string, ISettingsSerializer>();

        /// <summary>
        /// Collection of settings caching currently registered
        /// </summary>
        private readonly IDictionary<string, ISettingsCache> caches = new Dictionary<string, ISettingsCache>();

        /// <summary>
        /// Starts a settings provider configuration with the specified default storage.
        /// </summary>
        /// <typeparam name="TStorage">The type of the storage.</typeparam>
        /// <returns>
        /// The settings provider configuration
        /// </returns>
        public ISettingsProviderConfiguration ConfigureSettingsProvider<TStorage>() where TStorage : ISettingsStorage, new()
        {
            var settingsProviderConfigurator = new SettingsProviderConfiguration(this);
            settingsProviderConfigurator.WithDefaultStorage<TStorage>();
            return settingsProviderConfigurator;
        }

        /// <summary>
        /// Starts a settings provider configuration with the specified default storage.
        /// </summary>
        /// <param name="storage">The default settings storage to configure.</param>
        /// <returns>
        /// The settings provider configuration
        /// </returns>
        public ISettingsProviderConfiguration ConfigureSettingsProvider(ISettingsStorage storage)
        {
            var settingsProviderConfigurator = new SettingsProviderConfiguration(this);
            settingsProviderConfigurator.WithDefaultStorage(storage);
            return settingsProviderConfigurator;
        }

        /// <summary>
        /// Gets an existing settings storage by type, or adds the storage to the registered storages if the storage doesn't exist
        /// </summary>
        /// <typeparam name="TStorage">The type of the storage.</typeparam>
        /// <returns>The settings storage</returns>
        /// <exception cref="SettingsException">Invalid storage type specified</exception>
        internal ISettingsStorage GetStorage<TStorage>() where TStorage : ISettingsStorage, new()
        {
            var fullName = typeof(TStorage).FullName;

            if (string.IsNullOrEmpty(fullName))
            {
                throw new SettingsException("Invalid storage type specified");
            }

            if (!this.storages.ContainsKey(fullName))
            {
                var newStorage = new TStorage();
                this.storages[fullName] = newStorage;
                return newStorage;
            }

            var storage = this.storages[fullName];
            return storage;
        }

        /// <summary>
        /// Gets an existing settings serializer by type, or adds the serializer to the registered serializers if the serializer doesn't exist
        /// </summary>
        /// <typeparam name="TSerializer">The type of the serializer.</typeparam>
        /// <returns>
        /// The settings serializer
        /// </returns>
        /// <exception cref="SettingsException">Invalid serializer type specified</exception>
        internal ISettingsSerializer GetSerializer<TSerializer>() where TSerializer : ISettingsSerializer, new()
        {
            var fullName = typeof(TSerializer).FullName;

            if (string.IsNullOrEmpty(fullName))
            {
                throw new SettingsException("Invalid serializer type specified");
            }

            if (!this.serializers.ContainsKey(fullName))
            {
                var newSerializer = new TSerializer();
                this.serializers[fullName] = newSerializer;
                return newSerializer;
            }

            var serializer = this.serializers[fullName];
            return serializer;
        }

        /// <summary>
        /// Gets an existing settings cache by type, or adds the serializer to the registered serializers if the serializer doesn't exist
        /// </summary>
        /// <typeparam name="TCache">The type of the cache.</typeparam>
        /// <returns>
        /// The settings serializer
        /// </returns>
        /// <exception cref="SettingsException">Invalid serializer type specified</exception>
        internal ISettingsCache GetCache<TCache>() where TCache : ISettingsCache, new()
        {
            var fullName = typeof(TCache).FullName;

            if (string.IsNullOrEmpty(fullName))
            {
                throw new SettingsException("Invalid cache type specified");
            }

            if (!this.caches.ContainsKey(fullName))
            {
                var newCache = new TCache();
                this.caches[fullName] = newCache;
                return newCache;
            }

            var cache = this.caches[fullName];
            return cache;
        }
    }
}